package runner

import (
	"context"
	"fmt"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/jsonmessage"
	. "io"
	"operator/cicd/util"
	"os"
	"path/filepath"
	"strings"
)

const dockerfiledata = `FROM alpine
WORKDIR /home/
COPY ${exec_name} .
${other_file}
ENTRYPOINT ["./${exec_name}"]
`

type Builder struct {
	client *client.Client
	config *util.CICDConfig
	ctx    context.Context
}

func (b *Builder) Run() error {
	var err error
	dockerfile := filepath.Join(b.config.DefaultPath, "Dockerfile")
	if _, err = os.Stat(dockerfile); os.IsNotExist(err) {
		f, err := os.Create(dockerfile)
		str := strings.ReplaceAll(dockerfiledata, "${exec_name}", b.config.ExecName)

		otherStr := ""
		if len(b.config.NeedDirOrFile) > 0 {
			for _, d := range b.config.NeedDirOrFile {
				otherStr += "COPY " + d + " .\n"
			}
		}
		str = strings.ReplaceAll(str, "${other_file}", otherStr)

		_, err = f.Write([]byte(str))
		defer f.Close()
		if err != nil {
			return err
		}
	} else if err != nil {
		return err
	}

	reader, err := archive.TarWithOptions(b.config.TempPath, &archive.TarOptions{})
	if err != nil {
		return err
	}
	//fmt.Println(b.config.TempPath)
	defer func() {
		os.RemoveAll(b.config.TempPath)
		os.Remove(filepath.Join(b.config.DefaultPath, b.config.ExecName))
	}()
	t := fmt.Sprintf("%s:%s", b.config.ImageName, b.config.Version)
	tags := []string{t}

	resp, err := b.client.ImageBuild(b.ctx, reader, types.ImageBuildOptions{
		Remove:      true,
		ForceRemove: true,
		Tags:        tags,
	})
	if err != nil {
		return err
	}

	_, err = Copy(os.Stdout, resp.Body)
	if err != nil {
		return err
	}

	push, err := b.client.ImagePush(b.ctx, t, types.ImagePushOptions{
		RegistryAuth: b.config.AuthBase,
	})
	if err != nil {
		return err
	}

	err = jsonmessage.DisplayJSONMessagesToStream(push, NewOut(os.Stdout), nil)
	if err != nil {
		return err
	}

	return nil
}

func NewBuilder(ctx context.Context, config *util.CICDConfig, client *client.Client) *Builder {
	return &Builder{
		client: client,
		config: config,
		ctx:    ctx,
	}
}
